package design_patterns_and_best_practices_in_java;

import java.util.Stack;

interface Expression {
    public float interpret();
}

/**
 * Created with IntelliJ IDEA.
 * Description:
 *
 * @author lzy
 * @create 2019-11-14 下午12:03
 */
public class Chapter3 {
    public static void main(String[] args) {
        Evaluator evaluator = new Evaluator();
        System.out.println(evaluator.evaluate("2 3 +"));
        System.out.println(evaluator.evaluate(" 4 3 -"));
        System.out.println(evaluator.evaluate("4 3 - 2 +"));
    }
}

class Number implements Expression {
    private float number;

    public Number(float number) {
        this.number = number;
    }

    @Override
    public float interpret() {
        return number;
    }
}

class Plus implements Expression {
    private Expression left;
    private Expression right;

    public Plus(Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public float interpret() {
        return left.interpret() + right.interpret();
    }
}

class Minus implements Expression {
    private Expression left;
    private Expression right;

    public Minus(Expression right, Expression left) {
        this.left = left;
        this.right = right;
    }

    @Override
    public float interpret() {
        return left.interpret() - right.interpret();
    }
}

class Evaluator {
    public float evaluate(String expression) {
        Stack<Expression> stack = new Stack<>();
        float result = 0;
        for (String token : expression.split(" ")) {
            if (isOperator(token)) {
                Expression exp = null;
                if ("+".equals(token)) {
                    exp = stack.push(new Plus(stack.pop(), stack.pop()));
                } else if ("-".equals(token)) {
                    exp = stack.push(new Minus(stack.pop(), stack.pop()));
                }

                if (null != exp) {
                    result = exp.interpret();
                    stack.push(new Number(result));
                }
            }
            if (isNumber(token)) {
                stack.push(new Number(Float.parseFloat(token)));
            }
        }

        return result;
    }

    private boolean isNumber(String token) {
        try {
            Float.parseFloat(token);
            return true;
        } catch (NumberFormatException e) {
            return false;
        }
    }

    private boolean isOperator(String token) {
        return "-".equals(token) || "+".equals(token);
    }
}